#include <random>
#include <sstream>
#include <iomanip>
#include "Account.h"


Account::Account(const std::string& owner, const std::string& id)
    : ownerName(owner)
    , accountId(id)
    , balance(0.0) {}

void Account::addTransaction(const Transaction& transaction) {
    transactions.push_back(transaction);
    if (transaction.getSourceAccountId() == accountId) {
        updateBalance(-transaction.getAmount());
    }
    if (transaction.getDestinationAccountId() == accountId) {
        updateBalance(transaction.getAmount());
    }
}

void Account::updateBalance(double amount) {
    balance += amount;
}

bool Account::transfer(IAccount& destination, double amount, const std::string& note) {
    if (amount <= 0 || amount > balance) return false;
    
    Transaction trans(accountId, destination.getAccountId(), amount, "TRANSFER", note);
    addTransaction(trans);
    destination.addTransaction(trans);
    return true;
}

// Generate account numbers with specific format: 62XX-YYYY-ZZZZ-AAAA
std::string generateAccountNumber(bool isSavings) {
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<> dis(0, 9999);
    
    std::stringstream ss;
    ss << "62" << (isSavings ? "21" : "22") << "-"
       << std::setw(4) << std::setfill('0') << dis(gen) << "-"
       << std::setw(4) << std::setfill('0') << dis(gen) << "-"
       << std::setw(4) << std::setfill('0') << dis(gen);
    return ss.str();
}

SavingsAccount::SavingsAccount(const std::string& owner)
    : Account(owner, generateAccountNumber(true)) {}

bool SavingsAccount::transfer(IAccount& destination, double amount, const std::string& note) {
    // Can only transfer to same customer's checking account
    if (destination.getOwnerName() != ownerName) return false;
    return Account::transfer(destination, amount, note);
}

CheckingAccount::CheckingAccount(const std::string& owner)
    : Account(owner, generateAccountNumber(false)) {}

bool CheckingAccount::deposit(double amount, const std::string& note) {
    if (amount <= 0) return false;
    
    Transaction trans("CASH", accountId, amount, "DEPOSIT", note);
    addTransaction(trans);
    return true;
}

bool CheckingAccount::withdraw(double amount, const std::string& note) {
    if (amount <= 0 || amount > balance) return false;
    
    Transaction trans(accountId, "CASH", amount, "WITHDRAW", note);
    addTransaction(trans);
    return true;
}